package net.yxsoft.service;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONObject;
import com.jfinal.kit.Prop;
import com.jfinal.kit.PropKit;
import com.jfinal.kit.Ret;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Page;
import com.jfinal.plugin.activerecord.Record;
import net.yxsoft.bean.FnFormParams;
import net.yxsoft.cache.ToolCache;
import net.yxsoft.chainmaker.InitClient;
import net.yxsoft.kit.CustomDb;
import net.yxsoft.kit.Helper;
import net.yxsoft.kit.JsoupFilter;
import net.yxsoft.kit.RSAKit;
import net.yxsoft.model.formdesigner.FnFormData;
import net.yxsoft.model.infrastructure.TsUser;
import net.yxsoft.quorum.MyERC721;
import net.yxsoft.quorum.QuorumKit;
import net.yxsoft.resource.CodeRes;
import net.yxsoft.resource.Res;
import net.yxsoft.service.common.BaseService;
import org.bouncycastle.util.encoders.Hex;
import org.chainmaker.pb.common.ChainmakerBlock;
import org.chainmaker.pb.common.ChainmakerTransaction;
import org.chainmaker.sdk.ChainClient;
import org.chainmaker.sdk.SdkException;
import org.web3j.abi.datatypes.Type;
import org.web3j.abi.datatypes.Uint;
import org.web3j.abi.datatypes.Utf8String;
import org.web3j.protocol.core.methods.response.EthBlock;
import org.web3j.protocol.core.methods.response.EthTransaction;
import rapid.core.Authuser;
import rapid.util.DateKit;
import rapid.util.StrKit;


import java.math.BigInteger;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class BlockchainManagementService extends BaseService {

    public static final BlockchainManagementService me = new BlockchainManagementService();


    /**
     * @return int
     * @throws
     * @MethodName: getChainBasicInfo
     * @Description: 获取指定链的当前块高
     * @param: chainId
     * @date 2023/12/4
     * @author fl
     * {
     * "Response": {
     * "Data": {
     * "BlockHeight": 6507,
     * "TransactionNum": 6508,
     * "NodeNum": 4,
     * "RunningTime": 2056519,
     * "ContractNum": 33,
     * "OrgNum": 4,
     * "UserNum": 1,
     * "AuthType": "permissionedwithcert"
     * },
     * "RequestId": "fa11a5f1-f45c-42bb-bbd2-a5aa684f7c1c"
     * }
     * }
     * <p>
     * // 从解析后的JSON数据中获取所需的信息
     * int blockHeight = responseData.getInt("BlockHeight");
     * int transactionNum = responseData.getInt("TransactionNum");
     * int nodeNum = responseData.getInt("NodeNum");
     * int runningTime = responseData.getInt("RunningTime");
     * int contractNum = responseData.getInt("ContractNum");
     * int orgNum = responseData.getInt("OrgNum");
     * int userNum = responseData.getInt("UserNum");
     * String authType = responseData.getStr("AuthType");
     */
    public JSONObject getChainBasicInfo(ChainClient chainClient, String chainId) throws Exception {

        Prop initProp = PropKit.use("init.properties");

        HttpResponse response = HttpRequest.get(initProp.get("ChainMakerBackendUrl") + "?ChainId=" + chainId + "&cmb=Decimal").execute();

        // 获取响应内容
        String responseBody = response.body();
        System.out.println("Response Body: " + responseBody);

        // 解析JSON数据
        JSONObject jsonObject = new JSONObject(responseBody);
        JSONObject responseData = jsonObject.getJSONObject("Response").getJSONObject("Data");

        return responseData;
    }

    /**
     * 根据交易ID获取区块
     *
     * @param chainClient 区块链客户端
     * @param TX_ID       交易ID
     * @return 返回包含指定交易ID的区块信息
     * @throws Exception 发生错误时抛出异常
     */
    public ChainmakerBlock.BlockInfo getBlockByTxId(ChainClient chainClient, String TX_ID) throws Exception {

        ChainmakerBlock.BlockInfo blockInfo = null;
        try {
            blockInfo = chainClient.getBlockByTxId(TX_ID, false, 10000);
        } catch (SdkException e) {
            e.printStackTrace();
        }
        System.out.println(Hex.toHexString(blockInfo.getBlock().getHeader().getBlockHash().toByteArray()));
        return blockInfo;
    }

    /**
     * 获取区块高度
     *
     * @param chainClient 区块链客户端
     * @return 返回当前区块链的高度
     * @throws Exception 发生错误时抛出异常
     */
    public long getBlockHeight(ChainClient chainClient) throws Exception {

        long blockHeight = 0;
        try {
            blockHeight = chainClient.getCurrentBlockHeight(10000);
        } catch (SdkException e) {
            e.printStackTrace();
        }
        return blockHeight;
    }

    /**
     * 根据交易ID获取交易信息
     *
     * @param chainClient 区块链客户端
     * @param TX_ID       交易ID
     * @return 返回指定交易ID的交易信息
     * @throws Exception 发生错误时抛出异常
     */
    public ChainmakerTransaction.TransactionInfo getTxInfoByTxId(ChainClient chainClient, String TX_ID) throws Exception {

        ChainmakerTransaction.TransactionInfo transactionInfo = null;
        try {
            transactionInfo = chainClient.getTxByTxId(TX_ID, 10000);
        } catch (SdkException e) {
            e.printStackTrace();
        }
        return transactionInfo;
    }

    /**
     * 获取最新区块信息
     *
     * @param chainClient 区块链客户端
     * @return 返回最新的区块信息
     */
    public ChainmakerBlock.BlockInfo getLatestBlock(ChainClient chainClient) {
        ChainmakerBlock.BlockInfo blockInfo = null;
        try {
            blockInfo = chainClient.getLastBlock(false, 10000);
        } catch (SdkException e) {
            e.printStackTrace();
        }
        return blockInfo;
    }

    /**
     * 根据区块高度获取区块信息
     *
     * @param chainClient 区块链客户端
     * @param height      区块高度
     * @return 返回指定高度的区块信息
     */
    public static ChainmakerBlock.BlockInfo getBlockByHeight(ChainClient chainClient, long height) {
        ChainmakerBlock.BlockInfo blockInfo = null;
        try {
            blockInfo = chainClient.getBlockByHeight(height, false, 10000);
        } catch (SdkException e) {
            e.printStackTrace();
        }
        return blockInfo;
    }

    /**
     * 返回链上最新的  指令上链时间 orderStamp
     * 状态上链时间 stateStamp
     * 存证上链时间 evidenceStamp
     */
    public Map<String, String> getLatestTime(ChainClient chainClient) {

        long blockHeight = 0;
        try {
            blockHeight = chainClient.getCurrentBlockHeight(10000);
        } catch (SdkException e) {
            e.printStackTrace();
        }

        long blockStamp = 0;
        long transStamp = 0;

        /*for (long i = blockHeight; i >= 0; i--) {
            ChainmakerBlock.BlockInfo blockInfo = null;
            try {
                blockInfo = chainClient.getBlockByHeight(i, false, 10000);
                if (i == blockHeight) {
                    blockStamp = blockInfo.getBlock().getHeader().getBlockTimestamp();
                    transStamp = blockInfo.getBlock().getHeader().getBlockTimestamp();
                }

                for (int j = 0; j < blockInfo.getBlock().getTxsCount(); j++) {
                    ChainmakerTransaction.Transaction transaction = blockInfo.getBlock().getTxs(j);
                    System.out.println("\n" + transaction.getPayload().getMethod());
                    System.out.println("\n" + transaction.getResult().getContractResult().getMessage());
                    if (transaction.getPayload().getMethod().equalsIgnoreCase("setOrderData") &&
                            transaction.getResult().getContractResult().getMessage().equalsIgnoreCase("success")) {
                        orderStamp = transaction.getPayload().getTimestamp();
                    } else if (transaction.getPayload().getMethod().equalsIgnoreCase("setStateData") &&
                            transaction.getResult().getContractResult().getMessage().equalsIgnoreCase("success")) {
                        stateStamp = transaction.getPayload().getTimestamp();
                    } else if (transaction.getPayload().getMethod().equalsIgnoreCase("setEvidence") &&
                            transaction.getResult().getContractResult().getMessage().equalsIgnoreCase("success")) {
                        evidenceStamp = transaction.getPayload().getTimestamp();
                    }

                    if ((orderStamp > 0) && (stateStamp > 0) && (evidenceStamp > 0)) {
                        break;
                    }
                }

                if ((orderStamp > 0) && (stateStamp > 0) && (evidenceStamp > 0)) {
                    break;
                }
            } catch (SdkException e) {
                e.printStackTrace();
            }
        }
*/
        Map<String, String> mapObj = new HashMap<>();
        if (blockHeight > 0) {
            ChainmakerBlock.BlockInfo blockInfo = null;
            try {
                blockInfo = chainClient.getBlockByHeight(blockHeight, false, 10000);
                blockStamp = blockInfo.getBlock().getHeader().getBlockTimestamp();
                transStamp = blockInfo.getBlock().getHeader().getBlockTimestamp();

                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S");
                Record rd = Db.findFirst("select * from fn_form_data where attrib_01 = ? order by last_upd desc", "080608a331c4435ba313a487beca105a");
                if (rd != null) {
                    String sE = rd.getStr("last_upd");
                    LocalDateTime dateTime = LocalDateTime.parse(sE, formatter);
                    mapObj.put("evidenceStamp", getTimeDifference(dateTime));
                }

                Record rd1 = Db.findFirst("select * from fn_form_data where attrib_01 = ? and attrib_54 = '指令数据' order by last_upd desc", "273fc75a0c834f248203a272f8ca7840");
                if (rd != null) {
                    String sO = rd1.getStr("last_upd");
                    LocalDateTime dateTime = LocalDateTime.parse(sO, formatter);
                    mapObj.put("orderStamp", getTimeDifference(dateTime));
                }

                Record rd2 = Db.findFirst("select * from fn_form_data where attrib_01 = ? and attrib_54 = '状态数据'  order by last_upd desc", "273fc75a0c834f248203a272f8ca7840");
                if (rd2 != null) {
                    String sS = rd2.getStr("last_upd");
                    LocalDateTime dateTime = LocalDateTime.parse(sS, formatter);
                    mapObj.put("stateStamp", getTimeDifference(dateTime));
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        mapObj.put("blockStamp", getTimeDifference(convertLongToLocalDateTime(blockStamp)));
        mapObj.put("transStamp", getTimeDifference(convertLongToLocalDateTime(transStamp)));

        return mapObj;
    }

    public static LocalDateTime convertLongToLocalDateTime(long timestamp) {
        // 将Instant对象转换为LocalDateTime对象
        return LocalDateTime.ofInstant(
                Instant.ofEpochSecond(timestamp),
                ZoneId.systemDefault());
    }

    /**
     * 返回时间间隔时长[天前,小时前,分钟前,秒前]
     */
    public static String getTimeDifference(LocalDateTime time) {
        LocalDateTime now = LocalDateTime.now(); // 当前时间
        Duration duration = Duration.between(time, now);
        long seconds = Math.abs(duration.getSeconds());
        long minutes = Math.abs(duration.toMinutes());
        long hours = Math.abs(duration.toHours());
        long days = Math.abs(duration.toDays());
        if (days > 0) {
            return days + "天前";
        } else if (hours > 0) {
            return hours + "小时前";
        } else if (minutes > 0) {
            return minutes + "分钟前";
        } else {
            return seconds + "秒前";
        }
    }

}
